﻿using System;
using System.Collections.Generic;
using System.IO;
using System.Text;
using ExcelTool;
using UnityEngine;

public class ConfigDataLoader
{
    private static ConfigDataLoader _instance;

    public static ConfigDataLoader Instance
    {
        get
        {
            if (_instance == null)
            {
                _instance = new ConfigDataLoader();
            }
            return _instance;
        }   
    }
    private static  string configDataPath = "Assets/BundleResource/ProtoData/ConfigDataBase.bytes"; 

    /// <summary>
    /// 配置加载器
    /// </summary>
    IDataLoader loader;

    /// <summary>
    /// 数据表加载信息集
    /// </summary>
    private static readonly Dictionary<string, CreateConfigScriptData> configDic = new Dictionary<string, CreateConfigScriptData>();
    
    /// <summary>
    /// 初始化
    /// </summary>
    public void InitData()
    {
#if UNITY_EDITOR
        loader = new EditorLoader();
#else
        loader = new DefaultLoader();
#endif
        loadConfigCallBack callBack = new loadConfigCallBack();
        callBack.SuccessCallBack += (data) =>
        {
            var str = Encoding.UTF8.GetString(data);
            var dataList = str.Split('\n');
            for (int i = 0; i < dataList.Length; i++)
            {
                if (string.IsNullOrEmpty(dataList[i]))
                {
                    continue;
                }

                var split = dataList[i].Split(':');
                var fileType = split[0];
                var fileName = split[1];
                var filePath = split[2].Trim('\r');
                var type = Type.GetType(fileType);
                configDic.Add(fileName, new CreateConfigScriptData(fileName, type, filePath));
            }
        };
        loader.LoadConfig(configDataPath, callBack);
    }
    
    /// <summary>
    /// 初始化 加载 数据
    /// </summary>
    public void LoadConfigTable(string[] loadList)
    {
        for (int i = 0; i < loadList.Length; i++)
        {
            CreateConfigScriptData config;
            if (!configDic.TryGetValue(loadList[i], out config))
            {
                Debug.LogError($"数据表 {loadList[i]} 不存在! 加载失败!");
                continue;
            }

            System.Object instance = Activator.CreateInstance(config.Type);
            loadConfigCallBack callBack = new loadConfigCallBack();
            callBack.SuccessCallBack += (data) =>
            {
                var obj = ProtoBuf.Meta.RuntimeTypeModel.Default.Deserialize(new MemoryStream(data), instance, config.Type);

                IConfigData configData = (IConfigData) obj;
                configData?.InitData();
            };
            loader.LoadConfig(config.VariableName, callBack);
        }
    }

    /// <summary>
    /// 加载所有表
    /// </summary>
    public void LoadAllConfigTable()
    {
        foreach (var value in configDic)
        {
            System.Object instance = Activator.CreateInstance(value.Value.Type);
            loadConfigCallBack callBack = new loadConfigCallBack();
            callBack.SuccessCallBack += (data) =>
            {
                var obj = ProtoBuf.Meta.RuntimeTypeModel.Default.Deserialize(new MemoryStream(data), instance, value.Value.Type);

                IConfigData configData = (IConfigData) obj;
                configData?.InitData();
            };
            loader.LoadConfig(value.Value.VariableName, callBack);
        }
    }

    /// <summary>
    /// 根据ID 和数据集类型 获取 对应数据
    /// </summary>
    /// <param name="id"></param>
    /// <typeparam name="T1">数据集类型</typeparam>
    /// <returns></returns>
    public global::ProtoBuf.IExtensible LoadData<T1>(int id) where T1 : IConfigData
    {
        var type = typeof(T1);
        IConfigData configData = Activator.CreateInstance(type) as IConfigData;
        var result = configData?.LoadDataById(id);
        return result;
    }

    /// <summary>
    /// 根据类型 获取 该类型 整张表 数据
    /// </summary>
    /// <typeparam name="T1"></typeparam>
    /// <typeparam name="T2"></typeparam>
    /// <returns></returns>
    public List<T2> LoadDataList<T1,T2>() where T1 : IConfigData where T2 : global::ProtoBuf.IExtensible
    {
        var type = typeof(T1);
        IConfigData configData = Activator.CreateInstance(type) as IConfigData;
        var result = configData?.DataList();
        var data = result.ConvertAll<T2>(input => { return (T2) input; });
        return data;
    }
}

/// <summary>
/// 脚本数据
/// </summary>
public class CreateConfigScriptData
{
    public CreateConfigScriptData(){}

    public CreateConfigScriptData(string excelName, Type typeName, string variableName)
    {
        this.ExcelName = excelName;
        this.Type = typeName;
        this.VariableName = variableName;
    }
    /// <summary>
    /// excel名
    /// </summary>
    public string ExcelName;
    /// <summary>
    /// 类型名
    /// </summary>
    public string TypeName;
    /// <summary>
    /// 变量名
    /// </summary>
    public string VariableName;
    /// <summary>
    /// 类型
    /// </summary>
    public Type Type;
}
